<?php

namespace common\observer\task\version;

use malkusch\lock\mutex\PHPRedisMutex;
use support\bootstrap\Redis;
use Throwable;
use common\model\TaskModel;
use support\SingletonTrait;
use common\model\ProjectModel;
use common\model\VersionModel;
use common\service\OrderService;
use common\model\OrderTaskListModel;
use Webman\Stomp\RetryAbleConsumer;
use teamones\dbeventObserver\interfaces\SplSubject;
use teamones\dbeventObserver\interfaces\SplObserver;

/**
 * 外包版本更新同步到甲方版本信息
 */
class OutsideVersionUpdateSyncToInsideVersion implements SplObserver, RetryAbleConsumer
{
    use SingletonTrait;

    /**
     * @inheritDoc
     */
    function update(SplSubject $subject): void
    {
        $version = $subject->getSubjectData();

        $task = model(TaskModel::class)->find($version['link_id']);
        $project = model(ProjectModel::class)->find($task['project_id']);
        if ($project['type'] != 'outsource') {
            return;
        }
        $orderTaskListItem = OrderService::getInstance()->getOrderTaskListItemByRealTaskId($task['id'], ['status' => OrderTaskListModel::STATUS_DEFAULT]);
        if (empty($orderTaskListItem)) {
            return;
        }
        $sourceTask = model(TaskModel::class)->find($orderTaskListItem['task_id']);
        if (empty($sourceTask)) {
            return;
        }
        $order = OrderService::getInstance()->getOrderByStepTaskId($task['id']);
        if (empty($order)) {
            return;
        }
        $sourceVersion = model(VersionModel::class)
            ->where([
                'link_id' => $sourceTask['id'],
                'module_id' => $version['module_id'],
                'project_id' => $sourceTask['project_id'],
                'number' => $version['number'],
            ])
            ->order("id desc")
            ->find();
        $updatedData = $subject->getSplNewData();
        try {
            // 检查内部项目是否已经存在该任务版本
            if (!empty($sourceVersion)) {
                $updatedData['id'] = $sourceVersion['id'];
                // 更新数据
                model(VersionModel::class)->save($updatedData);
                APP_DEBUG && trace('sync version to insource project,action [update]', 'DEBUG');
            } else {

                $mutex = new PHPRedisMutex([Redis::connection()->client()], "lock-version_sync_{$version['id']}", 10);
                $mutex->synchronized(function () use ($version, $sourceTask) {
                    // 添加数据
                    $newVersionData = $version;
                    $newVersionData['link_id'] = $sourceTask['id'];
                    $newVersionData['tenant_id'] = $sourceTask['tenant_id'];
                    $newVersionData['project_id'] = $sourceTask['project_id'];
                    $newVersionData['uuid'] = create_uuid();
                    unset($newVersionData['module_code'], $newVersionData['project_type'], $newVersionData['id']);
                    // 新建版本 or 更新版本信息
                    model(VersionModel::class)->add($newVersionData);
                    APP_DEBUG && trace('sync version to insource project,action [add]', 'DEBUG');
                });
            }
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
    }

    /**
     * 重试间隔
     * @return int
     */
    public function getTtr()
    {
        return 30;
    }

    /**
     * 能否重试
     * @param $attempt
     * @param $error
     * @return bool
     */
    public function canRetry($attempt, $error)
    {
        trace(format_exception_info($error), 'ERR');
        return $attempt <= 3;
    }
}
